using System.Collections;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.SceneManagement;
using UnityEngine.Serialization;

public class RoomGenerator : MonoBehaviour
{
    // 房间生成方向的枚举
    public enum Direction
    {
        Up,    // 向上
        Down,  // 向下
        Left,  // 向左
        Right  // 向右
    };

    public GameObject player; // 玩家对象
    public Direction direction; // 当前房间生成方向

    [FormerlySerializedAs("roomPrefab")] [Header("房间信息")]
    public GameObject roomPrefab_door;        // 普通房间预制件（门）
    public GameObject initialRoomPrefab; // 初始房间预制件
    public GameObject bossRoomPrefab;    // Boss 房间预制件
    public GameObject shopRoomPrefab; // 商店房间预制件
    public GameObject rewardRoomPrefab; // 奖励房间预制件
    public GameObject DreamRoomPrefab; //梦引房
    
    
    private bool bossRoomGenerated = false;//boss房
    private bool shopRoomGenerated = false; // 标记是否生成过商店房间
    private bool rewardRoomGenerated = false; // 标记是否生成过奖励房间
    private bool dreamRoomGenerated = false;//梦
    
    public int roomNumber; // 需要生成的房间数量
    private GameObject _endRoom; // 最终房间
    
    [Header("位置控制")]
    public Transform generatorPoint; // 当前生成点位置

    public float xoffset, yoffset; // X 和 Y 方向上的偏移量
    public LayerMask roomLayer; // 用于检测房间是否重叠的层
    public int maxStep; // 从起始房间到最远房间的最大步数

    // 存储房间数据的列表
    public List<Room> rooms = new List<Room>();

    // 房间分类列表
    List<GameObject> farRooms = new List<GameObject>(); // 距离最远的房间
    List<GameObject> lessFarRooms = new List<GameObject>(); // 距离次远的房间
    List<GameObject> oneWayRooms = new List<GameObject>(); // 只有一个通道的房间

    public WallType wallType; // 墙体类型对象

    public GameObject pathfinder; // 用于寻路的对象

    void Start()
    {
        // 循环生成指定数量的房间
        for (int i = 0; i < roomNumber; i++)
        {
            if (i == 0) // 生成初始房间
            {
                rooms.Add(Instantiate(initialRoomPrefab, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            }
            else // 生成普通房间
            {
                rooms.Add(Instantiate(roomPrefab_door, generatorPoint.position, Quaternion.identity).GetComponent<Room>());
            }

            // 移动生成点的位置
            ChangePointPos();
        }

        _endRoom = rooms[0].gameObject; // 初始化最终房间为第一个房间
        foreach (var room in rooms)
        {
            SetupRoom(room, room.transform.position); // 设置房间的门
        }

        FindEndRoom(); // 寻找距离最远的房间并生成 Boss 房间
        EnablePathfinder(); // 激活寻路组件
        GenerateSpecialRooms();// 生成shop和reward关
        //todo:上面方法里加梦引房
    }

    private void EnablePathfinder()
    {
        // 激活寻路组件（如果存在）
        if (pathfinder != null)
        {
            pathfinder.SetActive(true);
        }
    }

    void Update()
    {
        // 按下 P 键重新加载当前场景
        if (Input.GetKeyDown(KeyCode.P))
        {
            SceneManager.LoadScene(SceneManager.GetActiveScene().name);
        }
    }

    public void ChangePointPos()
    {
        // 随机更改生成点位置，直到生成点不与其他房间重叠
        do
        {
            direction = (Direction)Random.Range(0, 4); // 随机选择一个方向
            switch (direction)
            {
                case Direction.Up:
                    generatorPoint.position += new Vector3(0, yoffset, 0);
                    break;
                case Direction.Down:
                    generatorPoint.position += new Vector3(0, -yoffset, 0);
                    break;
                case Direction.Left:
                    generatorPoint.position += new Vector3(-xoffset, 0, 0);
                    break;
                case Direction.Right:
                    generatorPoint.position += new Vector3(xoffset, 0, 0);
                    break;
            }
        } while (Physics2D.OverlapCircle(generatorPoint.position, 0.2f, roomLayer)); // 检测是否与已有房间重叠
    }

    public void SetupRoom(Room newRoom, Vector3 roomPosition)
    {
        // 检查每个方向是否有相邻房间，并设置房间的门
        newRoom.roomUp = Physics2D.OverlapCircle(roomPosition + new Vector3(0, yoffset, 0), 0.2f, roomLayer);
        newRoom.roomDown = Physics2D.OverlapCircle(roomPosition + new Vector3(0, -yoffset, 0), 0.2f, roomLayer);
        newRoom.roomLeft = Physics2D.OverlapCircle(roomPosition + new Vector3(-xoffset, 0, 0), 0.2f, roomLayer);
        newRoom.roomRight = Physics2D.OverlapCircle(roomPosition + new Vector3(xoffset, 0, 0), 0.2f, roomLayer);
        newRoom.UpdateRoom(xoffset, yoffset); // 更新房间的门状态

        // 根据房间门的数量选择对应的墙体类型并实例化
        switch (newRoom.doorNumber)
        {
            case 1:
                if (newRoom.roomUp)
                    Instantiate(wallType.singleUp, roomPosition, Quaternion.identity);
                if (newRoom.roomDown)
                    Instantiate(wallType.singleBottom, roomPosition, Quaternion.identity);
                if (newRoom.roomLeft)
                    Instantiate(wallType.singleLeft, roomPosition, Quaternion.identity);
                if (newRoom.roomRight)
                    Instantiate(wallType.singleRight, roomPosition, Quaternion.identity);
                break;
            case 2:
                if (newRoom.roomLeft && newRoom.roomUp)
                    Instantiate(wallType.doubleLU, roomPosition, Quaternion.identity);
                if (newRoom.roomLeft && newRoom.roomRight)
                    Instantiate(wallType.doubleLR, roomPosition, Quaternion.identity);
                if (newRoom.roomLeft && newRoom.roomDown)
                    Instantiate(wallType.doubleLB, roomPosition, Quaternion.identity);
                if (newRoom.roomUp && newRoom.roomRight)
                    Instantiate(wallType.doubleUR, roomPosition, Quaternion.identity);
                if (newRoom.roomUp && newRoom.roomDown)
                    Instantiate(wallType.doubleUB, roomPosition, Quaternion.identity);
                if (newRoom.roomRight && newRoom.roomDown)
                    Instantiate(wallType.doubleRB, roomPosition, Quaternion.identity);
                break;
            case 3:
                if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomRight)
                    Instantiate(wallType.tripleLUR, roomPosition, Quaternion.identity);
                if (newRoom.roomLeft && newRoom.roomRight && newRoom.roomDown)
                    Instantiate(wallType.tripleLRB, roomPosition, Quaternion.identity);
                if (newRoom.roomDown && newRoom.roomUp && newRoom.roomRight)
                    Instantiate(wallType.tripleURB, roomPosition, Quaternion.identity);
                if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomDown)
                    Instantiate(wallType.tripleLUB, roomPosition, Quaternion.identity);
                break;
            case 4:
                if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomRight && newRoom.roomDown)
                    Instantiate(wallType.fourDoors, roomPosition, Quaternion.identity);
                break;
        }
    }

    public void  FindEndRoom()
    {
        // 找到与初始房间最远的房间，并标记为最终房间
        for (int i = 0; i < rooms.Count; i++)
        {
            if (rooms[i].stepToStart > maxStep)
                maxStep = rooms[i].stepToStart;
        }

        foreach (var room in rooms)
        {
            if (room.stepToStart == maxStep)
            {
                farRooms.Add(room.gameObject); // 加入最远房间列表
            }

            if (room.stepToStart == maxStep - 1)
            {
                lessFarRooms.Add(room.gameObject); // 加入次远房间列表
            }
        }

        // 从最远房间中选择一个单通道房间作为最终房间，如果没有则随机选择一个
        for (int i = 0; i < farRooms.Count; i++)
        {
            if (farRooms[i].GetComponent<Room>().doorNumber == 1)
            {
                oneWayRooms.Add(farRooms[i]);
            }
        }

        if (oneWayRooms.Count != 0)
        {
            _endRoom = oneWayRooms[Random.Range(0, oneWayRooms.Count)];
        }
        else
        {
            _endRoom = farRooms[Random.Range(0, farRooms.Count)];
        }

        GenerateBossRoom(_endRoom.transform.position,_endRoom); // 在最终房间旁生成 Boss 房间
    }

    public void GenerateBossRoom(Vector3 endRoomPosition,GameObject endRoom)
    {
        // 在最远房间旁生成 Boss 房间
        bool bossRoomGenerated = false;
        Direction[] directions = { Direction.Up, Direction.Down, Direction.Left, Direction.Right };
        Direction direction;//boss房在在最远房间的方向

        while (!bossRoomGenerated)
        {
            direction = directions[Random.Range(0, directions.Length)];
            Vector3 bossRoomPosition = endRoomPosition;//初始化

            // 根据方向计算 Boss 房间位置
            switch (direction)
            {
                case Direction.Up:
                    bossRoomPosition += new Vector3(0, yoffset, 0);
                    break;
                case Direction.Down:
                    bossRoomPosition += new Vector3(0, -yoffset, 0);
                    break;
                case Direction.Left:
                    bossRoomPosition += new Vector3(-xoffset, 0, 0);
                    break;
                case Direction.Right:
                    bossRoomPosition += new Vector3(xoffset, 0, 0);
                    break;
            }

            // 检查位置是否已有房间
            if (!Physics2D.OverlapCircle(bossRoomPosition, 0.2f, roomLayer))//是否重合
            {
                GameObject bossRoom = Instantiate(bossRoomPrefab, bossRoomPosition, Quaternion.identity); // 生成 Boss 房间
                SetupRoom(bossRoom.GetComponent<Room>(), bossRoomPosition); // 设置 Boss 房间门状态
                bossRoomGenerated = true;
                // 标注 Boss 房间
                bossRoom.name = "BossRoom";
                Debug.Log("Boss Room generated at " + bossRoomPosition);
                        
                UpdateAdjacentRoomDoors(endRoomPosition, direction); // 更新相邻房间门状态
                //todo：更新门和对应grip
                //思路：是获得两者都有的方向 用这个方向对应出获得新的walltype

            }
            else
            {
                // 生成 Boss 房间失败，尝试其他方向
                //Debug.LogWarning("生成 Boss 房间失败，尝试其他方向");
            }
        }
    }



    private void UpdateAdjacentRoomDoors(Vector3 roomPosition, Direction newRoomDirection) //这个方法出现的新方向只有一个
    {
        //todo：更新门和对应grip
        //思路：是获得两者都有的方向 用这个方向对应出获得新的walltype
        //删掉对应的门和walltype
        //门和walltype组在一起才是一个房间
        //（为什么一开始会分开？！！！）
        Collider2D adjacentRoomCollider = Physics2D.OverlapCircle(roomPosition, 0.2f, roomLayer);
        if (adjacentRoomCollider != null)
        {               
            Room adjacentRoom = adjacentRoomCollider.GetComponent<Room>();//获得销毁的房间
            Debug.Log(adjacentRoom);
            if (adjacentRoom != null)
            {
                //todo：获得旧房间和原有的方向
                // 从房间列表中移除旧房间
                rooms.Remove(adjacentRoom);

                // 获取旧房间的门状态
                bool originalRoomUp = adjacentRoom.roomUp;
                bool originalRoomDown = adjacentRoom.roomDown;
                bool originalRoomLeft = adjacentRoom.roomLeft;
                bool originalRoomRight = adjacentRoom.roomRight;

                // 销毁旧房间对象（门）
                Destroy(adjacentRoom.gameObject);
                // 销毁旧房间对象wall
            // 获取所有带有指定层的物体
                GameObject[] objects = GameObject.FindObjectsOfType<GameObject>();
                foreach (GameObject obj in objects)
                {
                    if (obj.layer == LayerMask.NameToLayer("roomLayer")) // 替换为你的层名称
                    {
                        if (Vector2.Distance(obj.transform.position, roomPosition) < 0.2f)
                        {
                            Destroy(obj);
                            Debug.Log($"位于 {roomPosition} 附近的一次生成wall已销毁");
                        }
                    }
                }





                // 实例化新房间（对应单门）预制件并更新相应门的状态
                Room newRoom = Instantiate(roomPrefab_door, roomPosition, Quaternion.identity).GetComponent<Room>();
//
                //保留原有的门状态并添加新的门状态
                newRoom.roomUp = originalRoomUp;
                newRoom.roomDown = originalRoomDown;
                newRoom.roomLeft = originalRoomLeft;
                newRoom.roomRight = originalRoomRight;

                switch (newRoomDirection) //方向得反向
                {
                    case Direction.Up:
                        newRoom.roomUp = true;
                        break;
                    case Direction.Down:
                        newRoom.roomDown = true;
                        break;
                    case Direction.Left:
                        newRoom.roomLeft = true;
                        break;
                    case Direction.Right:
                        newRoom.roomRight = true;
                        break;
                }

//
                // 更新房间数据列表
                rooms.Add(newRoom);

                // 更新新房间的门和墙体
                newRoom.UpdateRoom(xoffset, yoffset);

                switch (newRoom.doorNumber)
                {
                    case 1:
                        if (newRoom.roomUp)
                            Instantiate(wallType.singleUp, roomPosition, Quaternion.identity);
                        if (newRoom.roomDown)
                            Instantiate(wallType.singleBottom, roomPosition, Quaternion.identity);
                        if (newRoom.roomLeft)
                            Instantiate(wallType.singleLeft, roomPosition, Quaternion.identity);
                        if (newRoom.roomRight)
                            Instantiate(wallType.singleRight, roomPosition, Quaternion.identity);
                        break;
                    case 2:
                        if (newRoom.roomLeft && newRoom.roomUp)
                            Instantiate(wallType.doubleLU, roomPosition, Quaternion.identity);
                        if (newRoom.roomLeft && newRoom.roomRight)
                            Instantiate(wallType.doubleLR, roomPosition, Quaternion.identity);
                        if (newRoom.roomLeft && newRoom.roomDown)
                            Instantiate(wallType.doubleLB, roomPosition, Quaternion.identity);
                        if (newRoom.roomUp && newRoom.roomRight)
                            Instantiate(wallType.doubleUR, roomPosition, Quaternion.identity);
                        if (newRoom.roomUp && newRoom.roomDown)
                            Instantiate(wallType.doubleUB, roomPosition, Quaternion.identity);
                        if (newRoom.roomRight && newRoom.roomDown)
                            Instantiate(wallType.doubleRB, roomPosition, Quaternion.identity);
                        break;
                    case 3:
                        if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomRight)
                            Instantiate(wallType.tripleLUR, roomPosition, Quaternion.identity);
                        if (newRoom.roomLeft && newRoom.roomRight && newRoom.roomDown)
                            Instantiate(wallType.tripleLRB, roomPosition, Quaternion.identity);
                        if (newRoom.roomDown && newRoom.roomUp && newRoom.roomRight)
                            Instantiate(wallType.tripleURB, roomPosition, Quaternion.identity);
                        if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomDown)
                            Instantiate(wallType.tripleLUB, roomPosition, Quaternion.identity);
                        break;
                    case 4:
                        if (newRoom.roomLeft && newRoom.roomUp && newRoom.roomRight && newRoom.roomDown)
                            Instantiate(wallType.fourDoors, roomPosition, Quaternion.identity);
                        break;
                }

            }
        }
    }



    public void MoveToNextRoom(Door.DoorDirection direction)
    {
        // 根据玩家当前房间的位置和方向计算下一个房间的位置
        Vector3 currentRoomPosition = player.transform.position;

        // 计算下一个房间的位置   
        Vector3 nextRoomPosition = currentRoomPosition;
        switch (direction)
        {
            case Door.DoorDirection.Up:
                nextRoomPosition += new Vector3(0, yoffset - 8.7f, 0);
                break;
            case Door.DoorDirection.Down:
                nextRoomPosition += new Vector3(0, -yoffset + 8f, 0);
                break;
            case Door.DoorDirection.Left:
                nextRoomPosition += new Vector3(-xoffset + 14f, 0, 0);
                break;
            case Door.DoorDirection.Right:
                nextRoomPosition += new Vector3(xoffset - 13f, 0, 0);
                break;
        }

        // 将玩家移动到下一个房间的位置
        player.transform.position = nextRoomPosition;
    }

    void GenerateSpecialRooms()
    {
        // 找到所有边缘房间
        List<GameObject> edgeRooms = new List<GameObject>();
        foreach (var room in rooms)
        {
            if (IsEdgeRoom(room))
            {
                edgeRooms.Add(room.gameObject);
            }
        }
        //todo:生成梦引房
        if (!shopRoomGenerated && edgeRooms.Count > 0)
        {
            GenerateSpecialRoom(edgeRooms, DreamRoomPrefab, "DreamRoom");
            dreamRoomGenerated = true;
        }
        // 生成商店房间
        if (!shopRoomGenerated && edgeRooms.Count > 0)
        {
            GenerateSpecialRoom(edgeRooms, shopRoomPrefab, "ShopRoom");
            shopRoomGenerated = true;
        }

        // 生成奖励房间
        if (!rewardRoomGenerated && edgeRooms.Count > 0)
        {
            GenerateSpecialRoom(edgeRooms, rewardRoomPrefab, "RewardRoom");
            rewardRoomGenerated = true;
        }
        
    }

    // 判断是否为边缘房间
    bool IsEdgeRoom(Room room)
    {
        Vector3 position = room.transform.position;
        bool upEmpty = !Physics2D.OverlapCircle(position + new Vector3(0, yoffset, 0), 0.2f, roomLayer);
        bool downEmpty = !Physics2D.OverlapCircle(position + new Vector3(0, -yoffset, 0), 0.2f, roomLayer);
        bool leftEmpty = !Physics2D.OverlapCircle(position + new Vector3(-xoffset, 0, 0), 0.2f, roomLayer);
        bool rightEmpty = !Physics2D.OverlapCircle(position + new Vector3(xoffset, 0, 0), 0.2f, roomLayer);

        return upEmpty || downEmpty || leftEmpty || rightEmpty;
    }

    // 生成特殊房间（商店或奖励房间）
    void GenerateSpecialRoom(List<GameObject> edgeRooms, GameObject specialRoomPrefab, string roomName)
    {
        bool specialRoomGenerated = false;
        
        // 当特殊房间未生成且有可用边缘房间时进行循环
        while (!specialRoomGenerated && edgeRooms.Count > 0)
        {
            int index = Random.Range(0, edgeRooms.Count);// 随机选择一个边缘房间
            GameObject edgeRoom = edgeRooms[index]; // 获取边缘房间
            edgeRooms.RemoveAt(index);       // 从列表中移除该房间

            Vector3 specialRoomPosition = edgeRoom.transform.position;
            Direction direction = (Direction)Random.Range(0, 4);
            switch (direction)
            {
                case Direction.Up:
                    specialRoomPosition += new Vector3(0, yoffset, 0);
                    break;
                case Direction.Down:
                    specialRoomPosition += new Vector3(0, -yoffset, 0);
                    break;
                case Direction.Left:
                    specialRoomPosition += new Vector3(-xoffset, 0, 0);
                    break;
                case Direction.Right:
                    specialRoomPosition += new Vector3(xoffset, 0, 0);
                    break;
            }

            // 检查位置是否已有房间
            if (!Physics2D.OverlapCircle(specialRoomPosition, 0.2f, roomLayer))
            {
               // GameObject specialRoom =
                    //Instantiate(specialRoomPrefab, specialRoomPosition, Quaternion.identity); // 生成特殊房间
                //specialRoom.name = roomName;
                Room newRoom = Instantiate(specialRoomPrefab, specialRoomPosition, Quaternion.identity).GetComponent<Room>();
                newRoom.name = roomName;
                // 设置房间门状态
                //SetupRoom(specialRoom.GetComponent<Room>(), specialRoomPosition);
                
                switch(GetReverseDirection(direction))//确认门的位置
                {
                    case Direction.Up:
                       
                        newRoom.roomUp = true;
                        break;
                    case Direction.Down:
                        
                        newRoom.roomDown = true;
                        break;
                    case Direction.Left:
                       
                        newRoom.roomLeft = true;
                        break;
                    case Direction.Right:
                        newRoom.roomRight = true;
                        break;
                }
                
                switch(GetReverseDirection(direction))//生成对应墙壁（后面是不同关卡的prefab）
                {
                    case Direction.Up:
                       
                        Instantiate(wallType.upRoom, specialRoomPosition, Quaternion.identity);
                        break;
                    case Direction.Down:
                        
                        Instantiate(wallType.downRoom, specialRoomPosition, Quaternion.identity);
                        break;
                    case Direction.Left:
                       
                        Instantiate(wallType.leftRoom, specialRoomPosition, Quaternion.identity);
                        break;
                    case Direction.Right: newRoom.roomLeft = true;
                        Instantiate(wallType.rightRoom, specialRoomPosition, Quaternion.identity);
                        break;
                }
                specialRoomGenerated = true;
                
                UpdateAdjacentRoomDoors(edgeRoom.transform.position, direction); // 更新相邻房间门状态
                
            }
        }
    }

    public Direction GetReverseDirection(Direction direction)
    {
        switch (direction)
        {
            case Direction.Up:
                return Direction.Down;
            case Direction.Down:
                return Direction.Up;
            case Direction.Left:
                return Direction.Right;
            case Direction.Right:
                return Direction.Left;
            default:
                Debug.LogError("出现意外的 direction 值");
                return Direction.Up;//异常情况
        }
        
    }


}

// 墙体类型的类，用于存储不同类型的墙体预制件
[System.Serializable]
public class WallType
{
    public GameObject singleLeft,
        singleRight,
        singleUp,
        singleBottom,
        doubleLU,
        doubleLR,
        doubleLB,
        doubleUR,
        doubleUB,
        doubleRB,
        tripleLUR,
        tripleLUB,
        tripleURB,
        tripleLRB,
        fourDoors,
        upRoom,
        downRoom,
        leftRoom,
        rightRoom;
}

